<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>医疗项目费用综合看板</title>
    <!-- 新增xlsx库 -->
    <script src="https://cdn.staticfile.org/xlsx/0.18.5/xlsx.full.min.js"></script>
    <script src="https://cdn.staticfile.org/echarts/5.4.0/echarts.min.js"></script>
    <style>
        .container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));
            gap: 20px;
            padding: 20px;
        }
        .chart-box {
            background: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            padding: 20px;
        }
        .indicators {
            display: flex;
            justify-content: space-around;
            margin-bottom: 20px;
        }
        .indicator-item {
            text-align: center;
            padding: 15px;
            border-radius: 8px;
            min-width: 200px;
        }
        .time-selector {
            padding: 20px;
            background: #f5f7fa;
            display: flex;
            gap: 20px;
            align-items: center;
        }
        #monthSelect {
            padding: 8px 15px;
            border-radius: 4px;
            border: 1px solid #dcdfe6;
            min-width: 200px;
        }
        .full-width {
            grid-column: 1 / -1;
        }
        /* 增加饼图容器空间 */
        #pieChart {
            padding: 30px !important;
        }
    </style>
</head>
<body>
    <div class="time-selector">
        <select id="monthSelect" onchange="updateCharts()"></select>
        <button onclick="importExcel()">导入Excel</button>
    </div>

    <div class="container">
        <div class="indicators" id="indicators"></div>
        
        <div class="chart-box" id="pieChart" style="height:500px;"></div>
        <div class="chart-box" id="barChart" style="height:500px;"></div>
        <div class="chart-box full-width" id="lineChart" style="height:500px;"></div>
    </div>

<script>
// 数据结构（示例数据）
let rawData = {
    "2023-12": {
        "房租": 52000,
        "工资": 145000,
        "利润": -160000,
        //...其他字段
    },
    "2024-01": {
        "房租": 52850.83,
        "物业": 3108.83,
        "税金": 4002.86,
        //...原始数据
        "利润": -168420.83
    },
    "2024-02": {
        "房租": 53500,
        "工资": 149000,
        "利润": -155000
    }
};

// 在文件顶部添加全局格式化函数
const formatter = {
    currency: value => `¥${parseFloat(value).toLocaleString(undefined, { 
        minimumFractionDigits: 2, 
        maximumFractionDigits: 2 
    })}`,
    percent: value => `${(value * 100).toFixed(1)}%`
};


// 图表初始化
let pieChart, barChart, lineChart;

function initCharts() {
    pieChart = echarts.init(document.getElementById('pieChart'));
    barChart = echarts.init(document.getElementById('barChart'));
    lineChart = echarts.init(document.getElementById('lineChart'));
    
    // 饼图配置
    pieChart.setOption({
        title: { 
            text: '费用构成分析',
            left: 'center',
            top: '20px'
        },
        legend: {
            orient: 'vertical',
            left: 'right',
            top: 'middle',
            itemGap: 15
        },
        tooltip: {
            trigger: 'item',
            formatter: params => 
                `${params.name}<br/>¥${params.value.toFixed(2)} (${params.percent.toFixed(1)}%)`
        },
        series: [{ 
            type: 'pie', 
            radius: '50%',
            label: {
                show: false // 完全隐藏所有标签
            },
            emphasis: { // 悬停时显示临时标签
                label: {
                    show: true,
                    position: 'outer',
                    formatter: '{b}\n¥{c} ({d}%)'
                }
            }
        }]
    });

    // 柱状图配置
    barChart.setOption({
        title: { 
            text: '费用项目TOP10',
            left: 'center',
            top: '20'
        },
        legend: {
            show: false // 柱状图默认不需要图例
        },
        grid: {
            top: 80
        },
        tooltip: { trigger: 'axis' },
        xAxis: { type: 'value' },
        yAxis: { type: 'category' },
        series: [{ type: 'bar', color: '#5470c6' }]
    });

    // 趋势图配置
    lineChart.setOption({
        title: { 
            text: '月度趋势分析',
            left: 'center',
            top: '20'
        },
        grid: {
            top: 80,
            bottom: 100 // 底部留出图例空间
        },
        tooltip: { trigger: 'axis' },
        xAxis: { type: 'category' },
        yAxis: { type: 'value' },
        legend: { 
            data: ['总费用', '项目收入', '利润'],
            bottom: 20, // 图例放在底部
            itemGap: 25 // 增加图例间距 
        },
        series: [
            { name: '总费用', type: 'line', smooth: true },
            { name: '项目收入', type: 'line', smooth: true },
            { name: '利润', type: 'line', smooth: true }
        ]
    });
}

// 改进的指标卡显示（保留两位小数）
function updateIndicators(data) {
    const container = document.getElementById('indicators');
    const formatNumber = num => 
        isNaN(num) ? 'N/A' : `¥${num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
    
    container.innerHTML = `
        <div class="indicator-item" style="background:#f0f9eb;">
            <h3>总费用</h3>
            <h2>${formatNumber(data.totalCost)}</h2>
        </div>
        <div class="indicator-item" style="background:#ecf5ff;">
            <h3>项目收入</h3>
            <h2>${formatNumber(data.income)}</h2>
        </div>
        <div class="indicator-item" style="background:#${data.profit >= 0 ? 'f0f9eb' : 'feeeed'}">
            <h3>利润</h3>
            <h2>${formatNumber(data.profit)}</h2>
        </div>
    `;
}

// 改进的日期格式化函数
function formatMonth(input) {
    const monthMap = {
        'jan': '01', 'feb': '02', 'mar': '03', 'apr': '04', 'may': '05', 'jun': '06',
        'jul': '07', 'aug': '08', 'sep': '09', 'oct': '10', 'nov': '11', 'dec': '12',
        'sept': '09' // 补充4字母缩写
    };
    
    // 新增：检查输入是否为有效Excel日期（大于0的整数）
    if (isNaN(input) || input <= 0 || !Number.isInteger(input)) {
        console.error(`无效的Excel日期序列号: ${input}`);
        return null;
    }
    // 处理Excel日期序列号（1900年日期系统）
    if (!isNaN(input)) {
        // 处理Excel日期序列号
        const jsDate = new Date(1900, 0, 1);
        jsDate.setDate(jsDate.getDate() + parseInt(input) - 2);
        
        const year = jsDate.getFullYear();
        const month = (jsDate.getMonth() + 1).toString().padStart(2, '0');
        return `${year}-${month}`;
    }

    // 原有格式处理
    const patterns = [
        // 模式2调整为：
        { regex: /([A-Za-z]{3,4})-(\d{4})/i, replacer: (_, m, y) => {
            const month = monthMap[m.toLowerCase()];
            return month ? `${y}-${month}` : input; // 无匹配时保留原输入
        }},
        { regex: /(\d{4})[年\/-](\d{1,2})/, replacer: (_, y, m) => `${y}-${m.padStart(2,'0')}` },
        // 新增模式：
        { regex: /(\d{1,2})[\/-](\d{4})/, replacer: (_, m, y) => {
            if (m > 12) return input; // 过滤无效月份
            return `${y}-${m.padStart(2,'0')}`;
        }}
    ];
    
    let formatted = input.toString().trim();
    for (const pattern of patterns) {
        if (pattern.regex.test(formatted)) {
            formatted = formatted.replace(pattern.regex, pattern.replacer);
            break;
        }
    }
    
    if (!/^\d{4}-\d{2}$/.test(formatted) || parseInt(formatted.split('-')[1]) > 12) {
        throw new Error(`无效的月份格式: ${input}`); // 或返回 { error: `无效的月份格式: ${input}` }
    }
    if (input instanceof Date) {
        const year = input.getFullYear();
        const month = (input.getMonth() + 1).toString().padStart(2, '0');
        return `${year}-${month}`;
    }
    return formatted;
}
   

// 增强版数值解析
function parseNumber(value) {
    if (typeof value === 'string') {
        // 去除货币符号和千分位逗号
        value = value.replace(/[¥$,]/g, '');
    }
    const num = parseFloat(value);
    return isNaN(num) ? 0 : Number(num.toFixed(2));
}

// 统一更新图表
function updateCharts() {
    const month = document.getElementById('monthSelect').value;
    const data = processData(month);

    // 更新指标
    updateIndicators(data);

    // 更新饼图（添加数值格式化）
    pieChart.setOption({
        grid: {
            top: 100 // 增加顶部留白区域
        },
        series: [{
            data: data.expenseItems.map(([name, value]) => ({
                name,
                value,
                // 在标签显示具体数值
                label: { 
                    formatter: `${name}\n¥${value.toFixed(2)}\n{percent|{d}%}`
                }
            }))
        }],
        tooltip: {
            formatter: params => 
                `${params.name}<br/>¥${params.value.toFixed(2)} (${params.percent.toFixed(1)}%)`
        }
    });

    // 更新柱状图（添加数值格式化）
    const top10 = data.expenseItems.slice(0, 10);
    barChart.setOption({
        yAxis: { data: top10.map(item => item[0]) },
        series: [{ 
            data: top10.map(item => item[1]),
            label: {
                show: true,
                position: 'right',
                formatter: params => `¥${params.value.toFixed(2)}`
            }
        }]
    });

    // 更新趋势图（统一格式化）
    lineChart.setOption({
        xAxis: { data: data.months },
        series: [
            { 
                name: '总费用', 
                data: data.trendData.costs,
                label: {
                    show: true,
                    formatter: params => params.value.toFixed(2)
                }
            },
            { 
                name: '项目收入', 
                data: data.trendData.income,
                label: {
                    show: true,
                    formatter: params => params.value.toFixed(2)
                }
            },
            { 
                name: '利润', 
                data: data.trendData.profit,
                label: {
                    show: true,
                    formatter: params => params.value.toFixed(2)
                }
            }
        ],
        tooltip: {
            trigger: 'axis',
            axisPointer: { type: 'cross' },
            valueFormatter: value => `¥${value.toFixed(2)}`
        }
    });
}

// 更新Excel解析逻辑
// function parseExcelData(workbook) {
//     const result = {};
    
//     workbook.SheetNames.forEach(sheetName => {
//         const worksheet = workbook.Sheets[sheetName];
//         // 添加日期单元格格式识别
//         const cellDates = true; // 关键设置
//         const jsonData = XLSX.utils.sheet_to_json(worksheet, { 
//             header: 1,
//             // rawNumbers: false,
//             cellDates: cellDates // 自动转换日期单元格
//         });
        
//         const headers = jsonData[0];
//         jsonData.slice(1).forEach(row => {
//             let originalMonth = row[0];
            
//             // 处理日期对象
//             if (originalMonth instanceof Date) {
//                 originalMonth = `${originalMonth.getFullYear()}-${(originalMonth.getMonth() + 1).toString().padStart(2, '0')}`;
//             }
            
//             const month = formatMonth(originalMonth);
//             if (!month) return;
            
//             result[month] = headers.reduce((acc, header, index) => {
//                 if (index > 0 && header) {
//                     acc[header] = parseNumber(row[index]);
//                 }
//                 return acc;
//             }, {});
//         });
//     });
    
//     return result;
// }

function parseExcelData(workbook) {
    const result = {};
    let parseErrors = [];
    
    workbook.SheetNames.forEach(sheetName => {
        try {
            const worksheet = workbook.Sheets[sheetName];
            const jsonData = XLSX.utils.sheet_to_json(worksheet, { 
                header: 1,
                cellDates: true,
                defval: 0 // 为空白单元格提供默认值0
            });
            
            // 检查是否有数据
            if (jsonData.length <= 1) {
                parseErrors.push(`工作表"${sheetName}"没有有效数据`);
                return;
            }
            
            const headers = jsonData[0].map(h => h ? h.toString().trim() : '');
            
            jsonData.slice(1).forEach((row, rowIndex) => {
                try {
                    let originalMonth = row[0];
                    if (!originalMonth) {
                        parseErrors.push(`工作表"${sheetName}"第${rowIndex+2}行: 缺少月份数据`);
                        return;
                    }
                    
                    const month = formatMonth(originalMonth);
                    if (!month) {
                        parseErrors.push(`工作表"${sheetName}"第${rowIndex+2}行: 无法解析月份"${originalMonth}"`);
                        return;
                    }
                    
                    result[month] = headers.reduce((acc, header, index) => {
                        if (index > 0 && header) {
                            acc[header] = parseNumber(row[index]);
                        }
                        return acc;
                    }, {});
                    
                } catch (e) {
                    parseErrors.push(`工作表"${sheetName}"第${rowIndex+2}行处理失败: ${e.message}`);
                }
            });
            
        } catch (e) {
            parseErrors.push(`处理工作表"${sheetName}"失败: ${e.message}`);
        }
    });
    
    // 如果有解析错误，显示给用户
    if (parseErrors.length > 0) {
        console.warn('数据解析警告:', parseErrors);
        alert(`数据导入完成，但有${parseErrors.length}个问题:\n${parseErrors.slice(0, 5).join('\n')}${parseErrors.length > 5 ? '\n...更多错误请查看控制台' : ''}`);
    }
    
    return result;
}

// 改进后的数据导入函数
// function importExcel() {
//     const input = document.createElement('input');
//     input.type = 'file';
//     input.accept = '.xlsx, .xls';
    
//     input.onchange = async e => {
//         const file = e.target.files[0];
//         if (!file) return;

//         try {
//             const reader = new FileReader();
//             reader.onload = function(e) {
//                 const data = new Uint8Array(e.target.result);
//                 const workbook = XLSX.read(data, { type: 'array' });
                
//                 // 解析Excel数据
//                 const newData = parseExcelData(workbook);
//                 Object.assign(rawData, newData);
                
//                 // 更新时间选择器
//                 updateMonthSelector();
//                 updateCharts();
//             };
//             reader.readAsArrayBuffer(file);
//         } catch (error) {
//             alert('文件解析失败: ' + error.message);
//         }
//     };
    
//     input.click();
// }

function importExcel() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.xlsx, .xls';
    
    input.onchange = async e => {
        const file = e.target.files[0];
        if (!file) return;

        // 添加覆盖确认对话框
        const shouldOverwrite = confirm('是否覆盖现有数据？点击"确定"覆盖，点击"取消"追加数据');
        
        try {
            const reader = new FileReader();
            reader.onload = function(e) {
                const data = new Uint8Array(e.target.result);
                const workbook = XLSX.read(data, { type: 'array' });
                
                // 解析Excel数据
                const newData = parseExcelData(workbook);
                
                // 根据用户选择决定是覆盖还是追加数据
                if (shouldOverwrite) {
                    rawData = newData; // 完全覆盖原有数据
                } else {
                    Object.assign(rawData, newData); // 追加新数据
                }
                
                // 更新时间选择器
                updateMonthSelector();
                updateCharts();
                alert(`数据导入成功！共导入${Object.keys(newData).length}个月份的数据`);
            };
            reader.readAsArrayBuffer(file);
        } catch (error) {
            alert('文件解析失败: ' + error.message);
            console.error('解析错误:', error);
        }
    };
    
    input.click();
}

// 更新月份选择器
function updateMonthSelector() {
    const select = document.getElementById('monthSelect');
    select.innerHTML = '';
    
    Object.keys(rawData)
        .sort()
        .forEach(month => {
            const option = new Option(
                `${month.slice(0,4)}年${month.slice(5)}月`,
                month
            );
            select.add(option);
        });
    
    if (select.options.length > 0) {
        select.value = select.options[select.options.length-1].value;
    }
}

// 改进的数据处理函数（增加容错）
function processData(month) {
    const currentData = rawData[month] || {};
    
    const expenseItems = Object.entries(currentData)
        .filter(([key]) => !['费用合计','项目收款（扣除返款）','利润'].includes(key)) // 修正字段名
        .sort((a, b) => b[1] - a[1]);

    // 趋势数据准备
    const months = Object.keys(rawData).sort();
    const trendData = {
        costs: months.map(m => rawData[m]['费用合计'] || 0),
        income: months.map(m => rawData[m]['项目收款（扣除返款）'] || 0), // 修正字段名
        profit: months.map(m => rawData[m]['利润'] || 0)
    };

    return {
        currentData,
        expenseItems,
        trendData,
        months,
        totalCost: currentData['费用合计'] || 0,
        income: currentData['项目收款（扣除返款）'] || 0, // 修正字段名
        profit: currentData['利润'] || 0
    }
}

function validateData(data) {
    const requiredFields = ['费用合计', '项目收款（扣除返款）', '利润'];
    const warnings = [];
    
    Object.entries(data).forEach(([month, values]) => {
        // 检查必填字段
        requiredFields.forEach(field => {
            if (values[field] === undefined) {
                warnings.push(`${month}: 缺少必填字段"${field}"`);
            }
        });
        
        // 检查数据合理性
        if (values['利润'] !== undefined && values['费用合计'] !== undefined && 
            values['项目收款（扣除返款）'] !== undefined) {
            const calculatedProfit = values['项目收款（扣除返款）'] - values['费用合计'];
            if (Math.abs(calculatedProfit - values['利润']) > 1) {
                warnings.push(`${month}: 利润计算不一致 (${values['利润']} ≠ 收入${values['项目收款（扣除返款）']} - 费用${values['费用合计']})`);
            }
        }
    });
    
    return warnings;
}

// 初始化
window.onload = function() {
    // 示例数据初始化
    rawData = {
        "2024-01": {
            "房租": 52850.83,
            "物业": 3108.83,
            // ...其他字段
            "利润": -168420.83
        }
    };
    updateMonthSelector();
    initCharts();
    updateCharts();
    
    // 模拟动态更新
    setInterval(() => {
        const currentMonth = document.getElementById('monthSelect').value;
        // 随机更新当前月数据
        Object.keys(rawData[currentMonth]).forEach(key => {
            if(Math.random() > 0.8 && !['费用合计','项目收款','利润'].includes(key)) {
                rawData[currentMonth][key] *= (1 + (Math.random() - 0.5)/10);
            }
        });
        updateCharts();
    }, 5000);
}

// 添加响应式调整
function adjustLayout() {
    const width = window.innerWidth;
    
    // 小屏幕优化
    if (width < 768) {
        pieChart.setOption({
            legend: {
                orient: 'horizontal',
                bottom: 20,
                top: 'auto'
            },
            grid: { top: 60 }
        });
        
        lineChart.setOption({
            legend: {
                bottom: 10,
                itemGap: 15
            }
        });
    } else {
        pieChart.setOption({
            legend: {
                orient: 'vertical',
                left: 'right',
                top: 'middle'
            }
        });
    }
}

// 窗口自适应
// window.onresize = function() {
//     pieChart.resize();
//     barChart.resize();
//     lineChart.resize();
//     adjustLayout(); // 新增布局调整
// }
window.onload = function() {
    rawData = {}; // 初始为空数据
    updateMonthSelector();
    initCharts();
    
    // 如果没有数据，显示提示
    if (Object.keys(rawData).length === 0) {
        alert('请点击"导入Excel"按钮加载数据');
    }
}

</script>
</body>
</html>